package edu.cs.usask.ca.silver.util.parsers.fileparsers;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URISyntaxException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;

/**
 * 
 * AlpFileReader should be doing nothing but read .alp file and parse it to DOM
 * and XML
 * 
 * @author John Dorion, Yudi Xue
 */
public class AlpFileReader {

	// global file pointing to an xslt transform script that processes .alp
	// files.
	private static InputStream alpToXML;
	private static InputStream alpToPackage;

	/**
	 * Class constructor initialises the object cache hashtables and populates
	 * them with fake objects (for now).
	 * 
	 * @throws URISyntaxException
	 */
	public AlpFileReader() throws IOException, TransformerException,
			ParserConfigurationException {		
		alpToXML = this.getClass().getClassLoader().getResource(
				"AlpToXMLParser.xsl").openStream();
		alpToPackage = this.getClass().getClassLoader().getResource(
				"AlpToPackage.xsl").openStream();
	}

	private static Document CreateDOMDocument()
			throws ParserConfigurationException {
		return DocumentBuilderFactory.newInstance().newDocumentBuilder()
				.newDocument();
	}

	// creating a Transformer looks confusing. For clarity, removed the creation
	// to a separate method,
	// since the code appeared a few times through this file.
	private static Transformer CreateTransformer()
			throws TransformerConfigurationException,
			TransformerFactoryConfigurationError {
		TransformerFactory transfac = TransformerFactory.newInstance();
		Transformer trans = transfac.newTransformer();
		trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
		trans.setOutputProperty(OutputKeys.INDENT, "yes");
		return trans;
	}

	// creating a Transformer looks confusing. For clarity, removed the creation
	// to a separate method,
	// since the code appeared a few times through this file.
	private static Transformer CreateTransformer(Source source)
			throws TransformerConfigurationException,
			TransformerFactoryConfigurationError {
		TransformerFactory transfac = TransformerFactory.newInstance();
		Transformer trans = transfac.newTransformer(source);
		trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
		trans.setOutputProperty(OutputKeys.INDENT, "yes");
		return trans;
	}

	// creates a ParameterSet DOM Document from an Alp file. almost exactly the
	// same as buildParameterSetXMLFileFromAlp(). could
	// possibly be refactored.
	public Document buildParameterSetDOMFromAlp(File alpFile)
			throws TransformerException, ParserConfigurationException {

		Document outputDocument = CreateDOMDocument();
		Result DOMresult = new DOMResult(outputDocument);

		Source alpSource = new StreamSource(alpFile);
		Source xsltSource = new StreamSource(alpToXML);

		Transformer trans = CreateTransformer(xsltSource);
		trans.transform(alpSource, DOMresult); // Modifies outputDocument as a
		// side effect

		return outputDocument;
	}

	public Document buildPackageDOMFromAlp(File alpFile)
			throws TransformerException, ParserConfigurationException {

		Document outputDocument = CreateDOMDocument();
		Result DOMresult = new DOMResult(outputDocument);

		Source alpSource = new StreamSource(alpFile);
		Source xsltSource = new StreamSource(alpToPackage);

		Transformer trans = CreateTransformer(xsltSource);
		trans.transform(alpSource, DOMresult); // Modifies outputDocument as a
		// side effect

		return outputDocument;
	}

	public String buildParameterSetXMLFromAlp(File alpFile)
			throws TransformerException, ParserConfigurationException {

		Transformer trans = CreateTransformer();

		// create string from xml tree
		StringWriter sw = new StringWriter();
		StreamResult result = new StreamResult(sw);
		Document resultDoc = buildParameterSetDOMFromAlp(alpFile);
		DOMSource source = new DOMSource(resultDoc);
		trans.transform(source, result);
		String xmlString = sw.toString();

		return xmlString;
	}

	public String returnPackageNameFromAlp(File alpFile)
			throws TransformerException, ParserConfigurationException {

		Transformer trans = CreateTransformer();

		// create string from xml tree
		StringWriter sw = new StringWriter();
		StreamResult result = new StreamResult(sw);
		Document resultDoc = buildPackageDOMFromAlp(alpFile);
		DOMSource source = new DOMSource(resultDoc);
		trans.transform(source, result);
		String xmlString = sw.toString();

		return xmlString;

	}

	// transforms an AnyLogic .alp file into an XML file according to our
	// specifications by using the xslt script.
	public void buildParameterSetXMLFileFromAlp(File alpFile, File outputFile)
			throws TransformerException, ParserConfigurationException {

		Result result = new StreamResult(outputFile);

		Source xmlSource = new StreamSource(alpFile);
		Source xsltSource = new StreamSource(alpToXML);

		Transformer optimus = CreateTransformer(xsltSource);
		optimus.transform(xmlSource, result);
	}

}